(*L'horrible, le non-voulu, l'impensable fichier interface.ml 
  travail de factorisation INDISPENSABLE ! *)

let main_init = GMain.init ()

(* On verifie que le fichier est bien un image *)
let good filename =
  let len = String.length (filename) in
    if (String.sub filename (len-4) 4) = ".bmp" ||
      (String.sub filename (len-4) 4) = ".png" ||
      (String.sub filename (len-4) 4) = ".jpg" then
   true
    else
    false

(* Fonction pour afficher une fenetre de selection de fichier *)
let file_selection s () =
  begin
    let file = GWindow.file_selection ~title:"File selection"
  ~border_width:10
  ~filename:"Choississez une image" () in
    (* On assigne a la nouvelle fenetre les interactions *)
      ignore (file#connect#destroy ~callback:GMain.Main.quit);
      ignore (file#cancel_button#connect#clicked
   ~callback:file#destroy);
      ignore (file#ok_button#connect#clicked ~callback:
		begin fun () ->
                  if good (file#filename) then
                    s := file#filename;
		end);
      ignore (file#ok_button#connect#clicked ~callback:file#destroy);
      file#show ();
      GMain.Main.main ()
 end	

(* Fonction pour crÃ©er un Gdk.Image Ã  partir d'un tableau Ã  deux
   dimensions de couleurs *)
let create_image g_image array = 
  let w,h = (Array.length array.(0), Array.length array)  in
    for y = 0 to h - 1 do
      for x = 0 to w - 1 do
	Gdk.Image.put_pixel g_image x y array.(x).(y);
      done;
    done

let sort_test x y =
  if x.Types.height <= y.Types.height then
    0
  else
    1

let write_color list =
  let canal_in = open_out "Color.txt" in
  let rec write l = match l with
      [] -> close_out canal_in
    | e::l -> let c = (string_of_int (e.Types.color)) in
              let h = (string_of_int (e.Types.height)) in
              let s = "Color = "^c^"; Height = "^h^"\n" in
              output canal_in s 0 (String.length s);
              write l;
  in
write !list

let make_image pixel img =
  for y = 0 to 49 do
    for x = 0 to 49 do
      Gdk.Image.put_pixel img x y pixel;
    done;
  done

let rec height_set2 count length list =
  main_init;
  let window2 = GWindow.window
   ~border_width:0
   ~width:300
   ~height:100 
   ~title:"Color" () in
  let vbox2 = GPack.vbox
    ~homogeneous:false
    ~border_width:0
    ~packing:window2#add () in
  let hbox2 = GPack.hbox
    ~homogeneous:false
    ~border_width:0
    ~packing:vbox2#add () in
  let image1 = GMisc.image
    ~packing:hbox2#add () in
  let entry = GEdit.entry
    ~packing:hbox2#add () in
  let hbuttonbox2 = GPack.button_box `HORIZONTAL
    ~layout:`SPREAD
    ~packing:(vbox2#pack ~expand:false ~fill:false) () in
  let button2 = GButton.button
    ~label:"Ok"
    ~packing:hbuttonbox2#add () in
  let visual2 = Gdk.Rgb.get_visual () in
  let img1 = Gdk.Image.create
    ~kind:`NORMAL
    ~visual:visual2
    ~width:50
    ~height:50 in
  window2#show ();
  make_image (List.nth !list !count).Types.color img1;
  image1#set_image img1;
  entry#set_text (string_of_int(!length));
  while (!count < !length) do
    ignore (button2#connect#clicked ~callback:begin fun () -> 
      if (entry#text <> "") then
	begin
          (List.nth !list !count).Types.height <- int_of_string(entry#text);
          count := !count + 1;
          if (!count < !length) then
            begin
              make_image (List.nth !list !count).Types.color img1;
              image1#set_image img1;
	      entry#set_text "";
            end
	  else
	    window2#destroy ();
	    GMain.Main.quit ();
	end
    end);
    GMain.main();
  done;
  list := List.sort sort_test !list;
  write_color list;
  !list

(*Fonction principale*)      
let main = 
  main_init;
  (* Fenetre principale *)
  let window = GWindow.window 
    ~border_width:0
    ~width:800
    ~height:600
    ~title:"Virgo Terris" () in

  (* Conteneur sÃ©parÃ© verticalement *) 
  let vbox1 = GPack.vbox
    ~homogeneous:false
    ~border_width:0
    ~packing:window#add () in

  (* CrÃ©ation des sous-menus *) 
  let file_menu = GMenu.menu () in
  let item1 = GMenu.menu_item ~label:"Open" ~packing:file_menu#append () in
  let item2 = GMenu.menu_item ~label:"Save" ~packing:file_menu#append () in
  let item3 = GMenu.menu_item ~label:"Quit" ~packing:file_menu#append () in

  let edit_menu = GMenu.menu () in
  let item4 = GMenu.menu_item ~label:"Vide" ~packing:edit_menu#append () in

  let help_menu = GMenu.menu () in
  let item5 = GMenu.menu_item ~label:"About" ~packing:help_menu#append
  () in
  let item6 = GMenu.menu_item ~label:"Manual"
    ~packing:help_menu#append () in

  (* CrÃ©ation de la barre de menu *)
  let menu_bar = GMenu.menu_bar ~packing:(vbox1#pack ~expand:false ~fill:false) () in

  (* CrÃ©ation des onglets du menu *)
  let file_item = GMenu.menu_item ~label:"File" () in
  let edit_item = GMenu.menu_item ~label:"Edit" () in
  let view_item = GMenu.menu_item ~label:"View" () in
  let setting_item = GMenu.menu_item ~label:"Settings" () in
  let help_item = GMenu.menu_item ~label:"Help" () in

  (* CrÃ©ation du conteur d'image *)
  let image1 = GMisc.image
    ~packing:vbox1#add () in
  
  (* Conteneur horizontale de boutton *)
  let hbuttonbox = GPack.button_box `HORIZONTAL
    ~layout:`SPREAD
    ~packing:(vbox1#pack ~expand:false ~fill:false) () in

  (* CrÃ©ation des bouttons *)
  let button1 = GButton.button
    ~label:"Start"
    ~packing:hbuttonbox#add () in
  
  let button2 = GButton.button
    ~label:"< Previous"
    ~packing:hbuttonbox#add () in

  let button3 = GButton.button
    ~label:"Next >"
    ~packing:hbuttonbox#add () in

  let button4 = GButton.button
    ~label:"Finish"
    ~packing:hbuttonbox#add () in

  (* CrÃ©ation de la zone oÃ¹ on va afficher les messages *)
  let s_c = GBin.scrolled_window
    ~height:150
    ~packing:(vbox1#pack ~expand:false ~fill:false) () in

  let file_path = ref "" in
    
  let step = ref 0 in 

  let memory = ref [] in

  let stock = ref [] in

  begin
    (* Mise en place du menu *)
    file_item#set_submenu file_menu;
    edit_item#set_submenu edit_menu;
    help_item#set_submenu help_menu;
    menu_bar#append file_item;
    menu_bar#append edit_item;
    menu_bar#append view_item;
    menu_bar#append setting_item;
    menu_bar#append help_item;

    s_c#set_border_width 1;

    (* Permet Ã  l'utilisateur d'ouvrir un fichier grÃ¢ce au menu *)
    ignore (item1#connect#activate ~callback: begin
	      fun() -> file_selection file_path ();
	    end);

    (* Affiche dans le conteneur limage choisis par l'utilisateur *)
    ignore (item1#connect#activate ~callback: begin 
	      fun() -> let image = BoarderProcess.transform
		(OImages.rgb24 (OImages.load !file_path [])) in
	      let visual1 = Gdk.Rgb.get_visual () in
              let img1 = Gdk.Image.create
                ~kind:`NORMAL
		~visual:visual1
                ~width:(Array.length image.(0))
		~height:(Array.length image) in
		create_image img1 image;
		image1#set_image img1;
		step := 0;
		memory := img1::[];
	    end);

    (* Quitter l'application grÃ¢ce au menu *)
    ignore (item3#connect#activate ~callback:GMain.Main.quit);

    (* On initialise les Ã©vÃ©nements pour la barre de menu *)
    ignore (item2#connect#activate ~callback: begin fun () -> () end);
    ignore (item4#connect#activate ~callback: begin fun () -> () end);
    ignore (item5#connect#activate ~callback: begin fun () -> () end);
    ignore (item6#connect#activate ~callback: begin fun () -> () end);

    (* Revenir Ã  la premiÃ¨re Ã©tape de l'image grÃ¢ce au boutton Start *)
    ignore (button1#connect#clicked ~callback:begin fun () -> 
	      match !step with
		  1 ->
		    if List.length !memory = 2 then
		      begin
			image1#set_image (List.nth !memory 1);
			step := 0;
		      end
		    else
		      begin
			image1#set_image (List.nth !memory 2);
			step := 0;
		      end
		| 2 -> begin
		    image1#set_image (List.nth !memory 2);   
		    step := 0; 
		  end
		| _ -> () 
	    end);

    (* Boutton Next : On avance dans le prÃ©-traitement ou affiche
       juste le rÃ©sultat si cela est dÃ©jÃ  fait *)
    ignore (button3#connect#clicked ~callback:begin fun () -> 
	      match !step with
		  0 -> if (List.length !memory) = 1 then
		      begin
			(* On trace les contours *)
			let image = BoarderProcess.transform
			  (OImages.rgb24 (OImages.load !file_path [])) in
			let image_f = BoarderProcess.border_f image
			  (BoarderProcess.border_w image)
			  (BoarderProcess.border_h image) in    
			let visual1 = Gdk.Rgb.get_visual () in
			let img1 = Gdk.Image.create
			  ~kind:`NORMAL
			  ~visual:visual1
			  ~width:(Array.length image.(0))
			  ~height:(Array.length image) in
			begin
			  create_image img1 image_f;
			  memory := img1::!memory;
			  image1#set_image img1;
			  step := !step + 1;
			end
		      end
		  else
		    begin
		      if (List.length !memory) = 2 then
			(* Le tracer des contours est deja fait, on affiche le rÃ©sultat *)
			begin
			  image1#set_image (List.nth !memory 0);
			  step := !step + 1;
			end
		      else
			begin
			  image1#set_image (List.nth !memory 1);
			  step := !step + 1; 
			end
		    end
		| 1 -> if List.length !memory = 2 then 
		    (* On fait le maillage de l'image *)
		    let image = BoarderProcess.transform
		      (OImages.rgb24 (OImages.load !file_path [])) in
		    let image_copy = BoarderProcess.transform
		      (OImages.rgb24 (OImages.load !file_path [])) in
		    let image_f = BoarderProcess.border_f image
                      (BoarderProcess.border_w image)
		      (BoarderProcess.border_h image) in
		    let listheight = ref (ColorParser.detection image_f) in 
		    let listheight2 = ref (height_set2 (ref 0) (ref
								  (List.length
								     !listheight))
					     listheight) in
		    let matpos = Sampler.create_vertices image_copy
		      !listheight2 in
		    let triangles = Sampler.triangulation matpos in
		    let grid = Sampler.create_grid image_f in
		    let visual1 = Gdk.Rgb.get_visual () in
		    let img1 = Gdk.Image.create
                      ~kind:`NORMAL
		      ~visual:visual1
                      ~width:(Array.length image.(0))
		      ~height:(Array.length image) in
                    begin
	              (*listheight := height_set2 (ref 0) (ref (List.length !listheight)) listheight;*)
                      triangles.(0) <- triangles.(0);
		      create_image img1 grid;
		      memory := img1::!memory;
		      image1#set_image img1;
		      step := !step + 1;
		      Obj_manager.write_obj triangles;
		    end
		  else
		    begin
		      (* Le maillage est deja fait, on l'affiche *)
		      image1#set_image (List.nth !memory 0);
		      step := !step + 1;
		    end
		| _ -> ()	      
    end);

    (* Boutton prÃ©cÃ©dent : le prÃ©-traitement est dÃ©jÃ  fait, on affiche
       juste l'Ã©tape souhaitÃ©e *)
    ignore (button2#connect#clicked ~callback:begin fun () -> 
	      match !step with
		  1 -> begin
		    if List.length !memory = 2 then
		      begin
			image1#set_image (List.nth !memory 1);
			step := 0;
		      end
		    else
		      begin
			image1#set_image (List.nth !memory 2); 
			step := 0;
		      end
		    end
		| 2 -> begin
		    image1#set_image (List.nth !memory 1);
		    step := 1;
		    end
		| _ -> ()
	    end);

    (* En fonction de l'Ã©tape courante, on applique tout le traitement
       Ã  l'image et passe directement Ã  la derniÃ¨re Ã©tape *)
    ignore (button4#connect#clicked ~callback:begin fun () -> 
	      if List.length !memory = 1 then
		(* On fait tout le traitement de l'image et l'insert Ã©tape par
		   Ã©tape dans la liste Ã  afficher *)
		begin
		  let image = BoarderProcess.transform
		    (OImages.rgb24 (OImages.load !file_path [])) in
		  let image_f = BoarderProcess.border_f image
                    (BoarderProcess.border_w image)
		    (BoarderProcess.border_h image) in
                  let pointed = ref image_f in
		  let visual1 = Gdk.Rgb.get_visual () in
		  let img1 = Gdk.Image.create
                    ~kind:`NORMAL
		    ~visual:visual1
                    ~width:(Array.length image.(0))
		    ~height:(Array.length image) in
		  let img2 = Gdk.Image.create
		    ~kind:`NORMAL
		    ~visual:visual1
		    ~width:(Array.length image.(0))
		    ~height:(Array.length image) in
		  begin
		    step := 2;
		    create_image img1 image_f;
		    memory := img1::!memory;
		    stock := ColorParser.detection image_f;
		    pointed := Sampler.create_grid image_f;
		    create_image img2 image_f;
		    memory := img2::!memory;
		    image1#set_image (List.nth !memory 0);
		  end
		end
	      else
		(* Si un des traitements est deja fait, on peut continuer
		   directement Ã  partie de cette Ã©tape *)
		begin
		  if List.length !memory = 2 then
		    begin 
		      let image = BoarderProcess.transform
			(OImages.rgb24 (OImages.load !file_path []))
		      in
		      let image_copy = BoarderProcess.transform
                    (OImages.rgb24 (OImages.load !file_path [])) in
		      let image_f = BoarderProcess.border_f image
			(BoarderProcess.border_w image)
			(BoarderProcess.border_h image) in
		      let listheight = ColorParser.detection image_f
		      in
		      let matpos = Sampler.create_vertices image_copy
			listheight in
		      let triangles = Sampler.triangulation matpos in
		      let grid = Sampler.create_grid image_f in
		      let visual1 = Gdk.Rgb.get_visual () in
		      let img1 = Gdk.Image.create
			~kind:`NORMAL
			~visual:visual1
			~width:(Array.length image.(0))
			~height:(Array.length image) in
		      begin
                        triangles.(0) <- triangles.(0);
			step := 2;
			create_image img1 grid;
			memory := img1::!memory;
			image1#set_image img1;
			Obj_manager.write_obj triangles;
		      end	  
		    end
		  else
		    begin
		      step := 2;
		      image1#set_image (List.nth !memory 0);
		    end
		end
	    end);

    (* On affiche la fenÃªtre *)
    window#show ();
    GMain.main ();
  end

